// 自定义 Electron 协议模块

import fs from 'fs';
import path from 'path';
import { protocol, net } from 'electron';

interface FileTypeMapKey {
    '.js': string;
    '.mjs': string;
    '.html': string;
    '.htm': string;
    '.json': string;
    '.css': string;
    '.svg': string;
    '.ico': string;
    '.png': string;
    '.jpg': string;
    '.map': string;
}

class RegisterProtocol {
    constructor() {}

    get baseName() {
        return path.resolve(__dirname, '../');
    }

    get fileTypeMap(): FileTypeMapKey {
        return {
            '.js': 'text/javascript',
            '.mjs': 'text/javascript',
            '.html': 'text/html',
            '.htm': 'text/html',
            '.json': 'application/json',
            '.css': 'text/css',
            '.svg': 'application/svg+xml',
            '.ico': 'image/vnd.microsoft.icon',
            '.png': 'image/png',
            '.jpg': 'image/jpeg',
            '.map': 'text/plain'
        };
    }

    public registerProtocol(): void {
        protocol.registerSchemesAsPrivileged([
            {
                scheme: 'app',
                privileges: {
                    standard: true,
                    secure: true,
                    supportFetchAPI: true,
                    allowServiceWorkers: true
                }
            }
        ]);
    }

    public charsetFile(ext: string): BufferEncoding | undefined {
        if (['.js', '.mjs', '.cjs', '.json', '.html', '.htm'].includes(ext)) {
            return 'utf-8';
        }
    }

    public protocolHandler(): void {
        protocol.handle('app', (req: GlobalRequest) => {
            const { host, pathname } = new URL(req.url);
            if (host === '.') {
                const filePath = path.normalize(`${host}${pathname}`);
                try {
                    const fileContent = fs.readFileSync(
                        path.resolve(this.baseName, filePath),
                        { encoding: this.charsetFile(path.extname(filePath)) }
                    );
                    return new Response(fileContent, {
                        headers: {
                            'content-type':
                                this.fileTypeMap[
                                    path.extname(
                                        filePath
                                    ) as keyof FileTypeMapKey
                                ]
                        }
                    });
                } catch (e) {
                    return new Response(
                        `bad request ${(e as unknown as { error: string }).error || (e as unknown as { message: string }).message}`,
                        {
                            status: 400
                        }
                    );
                }
            }

            return net.fetch(`${host}${pathname}`, req);
        });
    }
}

export default new RegisterProtocol();
